package org.log4jconfig.java.editor.hyperlink;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jdt.core.ICodeAssist;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.internal.core.SourceField;
import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
import org.eclipse.jdt.internal.ui.text.JavaWordFinder;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.hyperlink.AbstractHyperlinkDetector;
import org.eclipse.jface.text.hyperlink.IHyperlink;
import org.eclipse.ui.texteditor.ITextEditor;

@SuppressWarnings("restriction")
public class LoggerHyperlinkDetector extends AbstractHyperlinkDetector {

	/*
	 * @see
	 * org.eclipse.jface.text.hyperlink.IHyperlinkDetector#detectHyperlinks(
	 * org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion,
	 * boolean)
	 */
	public IHyperlink[] detectHyperlinks(ITextViewer textViewer,
			IRegion region, boolean canShowMultipleHyperlinks) {
		ITextEditor textEditor = (ITextEditor) getAdapter(ITextEditor.class);
		if (region == null || !(textEditor instanceof JavaEditor))
			return null;

		
		int offset = region.getOffset();

		IJavaElement input = EditorUtility.getActiveEditorJavaInput();
		if (input == null)
			return null;

		try {
			IDocument document = textEditor.getDocumentProvider().getDocument(
					textEditor.getEditorInput());
			IRegion wordRegion = JavaWordFinder.findWord(document, offset);
			if (wordRegion == null || wordRegion.getLength() == 0)
				return null;

			IJavaElement[] elements = null;
			elements = ((ICodeAssist) input).codeSelect(wordRegion.getOffset(),
					wordRegion.getLength());
			elements = selectOpenableElements(elements);
			if (elements.length == 0)
				return null;

			IHyperlink[] result = new IHyperlink[elements.length];
			for (int i = 0; i < elements.length; i++) {
				result[i] = new LoggerConfigurationHyperlink(wordRegion, input.getJavaProject());
			}
			return result;
		} catch (JavaModelException e) {
			return null;
		}
	}

	/**
	 * Selects the openable elements out of the given ones.
	 * 
	 * @param elements
	 *            the elements to filter
	 * @return the openable elements
	 * @throws JavaModelException
	 * @since 3.4
	 */
	private IJavaElement[] selectOpenableElements(IJavaElement[] elements)
			throws JavaModelException {
		List<IJavaElement> result = new ArrayList<IJavaElement>(elements.length);
		for (int i = 0; i < elements.length; i++) {
			IJavaElement element = elements[i];
			switch (element.getElementType()) {
			case IJavaElement.FIELD:
				IField field = (IField) element;
				String fieldTypeName = null;
				if (field instanceof SourceField) {
					String fieldType = Signature.getSignatureSimpleName(field
							.getTypeSignature());
					String[][] resolvedType = field.getDeclaringType()
							.resolveType(fieldType);
					if (resolvedType.length == 1) {
						fieldTypeName = Signature
								.toQualifiedName(resolvedType[0]);
					}
				} else {
					String typeSignature = field.getTypeSignature();
					fieldTypeName = field.getJavaProject().findType(
							Signature.toString(typeSignature))
							.getFullyQualifiedName();
				}

				if (fieldTypeName != null
						&& fieldTypeName.equals("org.apache.log4j.Logger")) {
					result.add(element);
				}

				break;
			default:
				break;
			}
		}
		return (IJavaElement[]) result.toArray(new IJavaElement[result.size()]);
	}
}
